84. 不要依赖线程调度器

      编写健壮、响应快、可移植程序的最佳方法是确保可运行线程的平均数量不显著大于处理器的数量。这使得线程调度器几乎没有选择:它只运行可运行线程,直到它们不再可运行为止。即使在完全不同的线程调度策略下,程序的行为也没有太大的变化。注意,可运行线程的数量与线程总数不相同,后者可能更高。正在等待的线程不可运行。

      线程不应该处于忙等待状态(busy-wait),而应该反复检查一个共享对象,等待它的状态发生变化。除了使程序容易受到线程调度器变化无常的影响之外,繁忙等待还大大增加了处理器的负载,还影响其他人完成工作。作为反面的极端例子,考虑一下 的不正确的重构实现:

      当面对一个几乎不能工作的程序时,而原因是由于某些线程相对于其他线程没有获得足够的 CPU 时间,那么 通过调用 Thread.yield 来「修复」程序 你也许能勉强让程序运行起来,但它是不可移植的。在一个 JVM 实现上提高性能的相同的 调用,在第二个 JVM 实现上可能会使性能变差,而在第三个 JVM 实现上可能没有任何影响。Thread.yield 没有可测试的语义。 更好的做法是重构应用程序,以减少并发运行线程的数量。

      总之,不要依赖线程调度器来判断程序的正确性。生成的程序既不健壮也不可移植。因此,不要依赖 或线程优先级。这些工具只是对调度器的提示。线程优先级可以少量地用于提高已经工作的程序的服务质量,但绝不应该用于「修复」几乎不能工作的程序。